﻿using DG.Tweening;
using ScFramework.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class Player : MonoBehaviour
{
 //   public float BasicUnit = 10;
    public float Speed = 10;
    public float JumpForce = 10;
    public float JumpTime = 1;
    public ActionState actionState = ActionState.Ground;
    public static Player Instance = null;
    public bool _isFree = true;
    public static bool _alive = false;
    public static bool Alive
    {
        get
        {
            return _alive;
        }
        set
        {
            _alive = value;
            if (!value)
            {
                Instance.ToFree();
                Instance.IsFree = false;
                if(GameObject.FindObjectOfType<Frame>() is Frame f)
                {
                    f.gameObject.SetActive(false);
                }
                //  ResetData(lstData);
            //    InstanceManager.Instance.Map.transform.DOKill(true);
                //InstanceManager.Instance.Map.transform.localPosition = Vector3.one/InstanceManager.Instance.Scale;
                Main.Instance.PopText("You are dead. Press 'R' to restart.");
            }
        }
    }
    public bool IsFree
    {
        get => _isFree;
        set
        {
            for (int i = 0; i < transform.childCount; i++)
            {
                transform.GetChild(i).gameObject.SetActive(value);
                if (transform.GetChild(i).GetComponent<Rigidbody2D>() != null)
                {

                    transform.GetChild(i).GetComponent<Rigidbody2D>().velocity = Vector3.zero;
                }
            }
            GetComponent<Slime>().SetCenter(Vector2.zero);
            rigid.simulated = value;
            rigid.velocity = Vector3.zero;
            _isFree = value;
        }
    }
    public Vector2 DownDir = new Vector2(0,-1);
    public float _scale = 1f;
    public float BottomLength = 10;
  //  public Triangle Tri = null;
    Rigidbody2D rigid;

    public TriData _triData = new TriData();
    public TriData TriData
    {
        get => _triData;
    }
    GameObject map;
    private void Awake()
    {
        rigid = GetComponent<Rigidbody2D>();
        Instance = this;
        map = GameObject.Find("Map");
    }
    public Vector2 RightVec
    {
        get
        {
            return UnsafeTool.TurnAngle(DownVec, Mathf.PI / 2);
        }
    }
    public Vector2 DownVec
    {
        get
        {
            return DownDir.normalized;
            /*var ans=UnsafeTool.TurnAngle(DownLine, Mathf.PI/2);
            if ((Vector3.Cross(ans, DownLine).z < 0) ^ (Vector3.Cross(Tri.Tris[0].Points[(DownDir + 2) % 3] - DownPoint, DownLine).z < 0))
            {
                return ans.normalized;
            }
            else
            {
                return - ans.normalized;
            }*/
            
        }
    }
   /* public Vector2 DownLine
    {
        get
        {
            
    //        return Tri.Tris[0].Points[(DownDir + 1) % 3]-Tri.Tris[0].Points[DownDir] ;
        }
    }
    public Vector2 DownPoint
    {
        get
        {
            return Tri.Tris[0].Points[DownDir];
        }
    }*/
    public float Scale
    {
        get
        {
            return _scale;
        }
        set
        {
            _scale = value;
            //   this.transform.position = map.transform.InverseTransformPoint(this.transform.position);
            map.transform.localScale=(Vector3.one/value);
        //    this.transform.position = map.transform.TransformPoint(this.transform.position);
            
            //        this.transform.localScale = Vector3.one * _scale;

        }
    }
    public Vector2 Pos
    {
        get
        {
            return (Vector2)transform.position+DownVec*5;
        }
    }
    private void OnDrawGizmos()
    {
        if (Application.isPlaying)
        {

        Gizmos.DrawLine(Pos, Pos + DownVec*50);
        var box = GetWorldDownDetectBox();
        MathTool.DrawCube(box.Item1, box.Item2, box.Item3);
            Gizmos.DrawWireSphere(transform.TransformPoint( GetComponent<Slime>().GetCenter()), 3);
        }

    }
    public void ToFree()
    {
        Debug.Log("ToFree");
        if (TriData.Points[0].VecEqu(TriData.Points[1]))
        {
            transform.position = TriData.Points[0];
        }
        else
        {

            transform.position = TriData.ToWorld(Main.Map).Center;
        }
        //Debug.Log(transform.position);
        IsFree = true;
            transform.GetComponent<Slime>().SetColor(Main.Instance.Config.MatDic.Find(s => s.Type == TriData.Type).Mat.color);
        if (InstanceManager.Instance.GetRelatedTri(TriData) != null)
        {

            if (InstanceManager.Instance.MapDic.ContainsKey(InstanceManager.Instance.GetRelatedTri(TriData)))
            {
                InstanceManager.Instance.MapDic[InstanceManager.Instance.GetRelatedTri(TriData)].Exit();
            }
        }
        TriData.Points = new List<Vector2> { transform.position, transform.position, transform.position };
   //     GetComponent<Slam>().SetCenter(Vector2.zero);
    }
    public void ToTri(TriData tri,int lst=-1)
    {
        ToFree();
        Debug.Log("ToTri");
        if (tri.Type == TriEnum.Orange)
        {
            return;
        }

        var lstTris = UnsafeTool.DeepCopyByJson(TriData);
        var dv = DownVec;
        IsFree = false;
        TriData.SetData(tri);
        int id = -1;
        float v = float.NegativeInfinity;
        for(int i = 0; i < 3; i++)
        {
            if (i == lst)
            {
                continue;
            }
            if (Vector2.Dot(TriData.GetVtr(i).TurnAngle(-Mathf.PI/2), dv) > v)
            {
                id = i;
                v = Vector2.Dot(TriData.GetVtr(i).TurnAngle(-Mathf.PI / 2), dv);
            }

        }
        if (lst != -1)
        {
            id = lst;
        }
        Scale =Mathf.Sqrt(UnsafeTool.GetArea(tri.Points.ToArray())/200);
        DownDir = TriData.GetDownVtr(id);
        transform.position = tri.Center/Scale;
        transform.GetComponent<Slime>().SetColor(Main.Instance.Config.MatDic.Find(s=>s.Type==TriData.Type).Mat.color);
        transform.GetComponent<Slime>().SetCenter(Vector2.zero);
        InstanceManager.Instance.MapDic[tri].Enter(tri.Type);
        /*if (InstanceManager.Instance.GetRelatedTri(lstTris) != null)
        {

            if (InstanceManager.Instance.MapDic.ContainsKey(InstanceManager.Instance.GetRelatedTri(lstTris)))
            {
                InstanceManager.Instance.MapDic[InstanceManager.Instance.GetRelatedTri(lstTris)].Exit();
            }
        }
        */
    }
    public Tuple<Vector2, Vector2, float> GetWorldDownDetectBox()
    {
        Vector2 pos = Pos+DownVec/2;
        Vector2 siz = new Vector2(BottomLength, 1)*0.9f;
        float angle = MathTool.VectorToAngle(RightVec);
        return new Tuple<Vector2, Vector2, float>(pos,transform.TransformVector(siz), angle);
    }
    public List<TriData>GetBox(Vector2 pos,Vector2 siz,float angle)
    {
        var lst = Physics2D.OverlapBoxAll(pos, siz, angle,LayerMask.GetMask("Ground"));
        List<TriData> ans = new List<TriData>();
        foreach(var x in lst)
        {
            ans.Add(x.GetComponent<MeshComp>().Tri);
        }
        return ans;

    }
    public Dictionary<TriData, int> GetOverlap(TriEnum Type)
    {
        var ans = new Dictionary<TriData, int>();
        for(int i = 1; i < transform.childCount; i++)
        {
            List<Collider2D> list = new List<Collider2D>();
            transform.GetChild(i).GetComponent<Collider2D>().OverlapCollider(new ContactFilter2D(), list);
            foreach(var x in list)
            {
                if (x.GetComponent<MeshComp>() == null)
                {
                    continue;
                }
                var t = x.GetComponent<MeshComp>().Tri;
                if (t.Type != Type) continue;
                if (ans.ContainsKey(t))
                {
                    ans[t]++;
                }
                else
                {
                    ans[t] = 1;
                }
            }
        }
        return ans;
    }
    float _jumpTime = float.NegativeInfinity;
    ActionState lst = ActionState.Dropping;
    float _dropTime = float.PositiveInfinity;
    private void Update()
    {
        if (IsFree)
        {

            float vx = 0;
                //MathTool.Project(rigid.velocity,RightVec).magnitude;
            float vy = MathTool.Project(rigid.velocity, DownVec).magnitude;
       //     Debug.Log("vy begin is " + vy);
            if(InputManager.Instance.GetButton("Left"))
            {
                vx -=  Speed;
            }
            if (InputManager.Instance.GetButton("Right"))
            {
                vx +=  Speed;
            }
            if (ActionState.Ground==actionState)
            {
                if (InputManager.Instance.GetButtonDown("Jump"))
                {
                    actionState = ActionState.Jumping;
                    _jumpTime = Time.time;

                }
                else
                {
                    var box = GetWorldDownDetectBox();
                    if (GetBox(box.Item1, box.Item2, box.Item3).Count == 0)
                    {
                        actionState = ActionState.Dropping;
                        vy = 20 ;
                    }
                }
            }else if (ActionState.Jumping == actionState)
            {
                if (InputManager.Instance.GetButtonUp("Jump")||Time.time-_jumpTime>JumpTime||MathTool.Project(rigid.velocity,DownVec).magnitude<JumpForce/2)
                {
                    //|| MathTool.Project(rigid.velocity, DownVec).magnitude < velocity ||
                    actionState = ActionState.Dropping;
                    vy = 20;
                    
                }
            }
            else
            {
                if (Time.time - _jumpTime > 0.1)
                {
                    var box = GetWorldDownDetectBox();
                    if (GetBox(box.Item1, box.Item2, box.Item3).Count > 0)
                    {
                        actionState = ActionState.Ground;
                    }
                }
            }
            if (ActionState.Jumping == actionState)
            {
       //         Debug.Log(MathTool.Project(RightVec, RightVec) + " " + (-DownVec * JumpForce * (Scale)));
                vy = -JumpForce ;
          //      rigid.velocity=MathTool.Project(RightVec,RightVec)+ (-DownVec * JumpForce *(Scale));
            }else if (ActionState.Dropping == actionState)
            {
                /*if (Vector3.Dot( rigid.velocity , DownVec) < 0)
                {
                    rigid.velocity =MathTool.Project(rigid.velocity, RightVec);
                }*/
            }
         //   Debug.Log($"{vx} {vy}");
            rigid.velocity = vx * RightVec + vy * DownVec;
            if (actionState == ActionState.Dropping && lst == ActionState.Dropping&&rigid.velocity.magnitude>100f)
            {
                if (_dropTime == float.PositiveInfinity)
                {
                    _dropTime = Time.time;
                }
                if (Time.time - _dropTime > 5f)
                {
                    Debug.Assert(Player.Alive == true);
                    Player.Alive = false;
                    _dropTime = float.PositiveInfinity;
                }
            }
            else
            {
                _dropTime = float.PositiveInfinity;
            }
            lst = actionState;
        }
        else
        {
            _dropTime = float.PositiveInfinity;
        }
    }
}


public enum ActionState
{
    Ground,Jumping,Dropping
}